/**
 * 微型的模板程序
 * 支持 JS 语句执行、JSONPath、模板方法、IF 判断标签
 */
define(function(require, exports, module) {

    /**
     * 匹配每个花号
     */
    function replaceValue(match, key) {   
        var value;
        if (key in this.data) {
            value = this.data[key]; // 此为最简单之情形
        } else if (key.indexOf('x_root.') != -1) {
            value = '';// 捕获 jsonPath 段并解析返回。当前是空字符串，@todo JSONPath
        } else if (execJS.test(key) === true) {
            value = parseJS.call(this, key);
        } else {
            value = '[没有该值的定义 undefined!]';
        }
        return value;
    }

    var execJS = /^\[([^\]]*)\]$/;
	/**
	 * 捕获 js 段并执行返回。
	 * @param {String} key
	 * @return {String}
	 */
    function parseJS(key) {
        var js = key.match(execJS), js = js[1],
        	fnBody = 'with(value){ return {0};} ', fnBody = fnBody.format(js),
        	fn = new Function('value', fnBody), 
        	value;

        try{
        	value = fn.call(this.tpl, this.data);
        }catch(e){
        	value = '[tpl]捕获 js 段失败，key/value:{0}/{1} '.format(key, value);
        	console.warn(value + e.toString());
        }
        return value;
    }

    // @todo 非捕获匹配未考虑好 要琢磨下
	var getIf_Eval = /<if\s*(?:eval="([\s\w\d=<>\.!'\|\(\)&]*)")[^>]*>/i; // 2012-12-26 加入一个  /s 空格
	var regexp = /{([^}\n]*)}/ig;
	function replaceIf(match, key){
		var _eval = match.match(getIf_Eval);
		if (_eval == null){
			throw "[tpl] if tag 必须配合 eval 属性";
		}else if(!_eval[1]){
			throw '匹配失败'; // 不是第一个元素，而是第二个才是！
		}
		
		_eval = _eval[1];	// 求出了表达式，但为字符串，不能直接求值。
		
		var isReturnTrueFn = new Function('value', 'with(value){ return ' + _eval + ';}');

		var ifReturnValue;
		try{
			ifReturnValue = isReturnTrueFn.call(this.tpl, this.data);
		}catch(e){
			console.warn('[replaceIf]执行{0}错误！'.format(_eval));
		}
		
		if (ifReturnValue){
			return key.replace(regexp, replaceValue.bind(this));
		}else{
			return ''; // 条件不充分，返回空字符串。
		}
	}

    // 匹配闭合tag的正则。
    var divBlock = '<{0}\\s*[^>]*>((?:(?=([^<]+))\\2|<(?!{0}\\s*[^>]*>))*?)<\/({0})>',
    	ifTag	= new RegExp(divBlock.format('if'), 'ig');
    
    /**
     * 实现 alert(tpl.replace('jjj{dd}jjj', {dd:'dfsdfsdfdf'}));
     * @param {String} tpl
     * @param {JSON}
     * @return {String}
     */
	function replaceTpl(tpl, json) {
        if (!tpl || !json)throw '[tpl] 没有模板或者数据';
        

		// if(!this instanceof module.exports){
		// 	throw "欲执行该函数，其作用域必须为 $$.tpl 类型!";
		// }
		var sendArgsByScope = {
        	tpl	: this,
        	data : json	
		};

        ifTag.lastIndex = 0;
        var html = (ifTag.test(tpl) === true) ? 
        			tpl.replace(ifTag, replaceIf.bind(sendArgsByScope)) : tpl;

        return html.replace(regexp, replaceValue.bind(sendArgsByScope));
    }
    exports.replace = replaceTpl;

    var tplTag = new RegExp(divBlock.format('tpl'), 'ig');

    /**
     * @param {String} m_tpl
     * @param {JSON}	dataSet 支持多层的JSON
     * @param {Function} everyFn 遍历数据每一项的执行的函数。
     */
    exports.renderList = {
    	tpl : null,
    	data : null,
    	everyFn : null,
    	apply : function(){
		    var self = this;
		    var data = this.data;
	        var everyFn = this.everyFn;
			// var match, tpl;
			// while ((match = tplTag.exec(m_tpl)) != null) {
			//    tpl = match[1];
			//    console.log(tpl);
			// }

	        if(typeof this.tpl == 'object')this.tpl = this.tpl.value; // for TEXTAREA HTMLElement
	        
		    
		    if(!data)
		    	throw '[tpl] 没有输入数据！';
		    else if(!this.tpl || typeof this.tpl != 'string')
		    	throw '[tpl] 没有输入模板！或者模板类型不正确，应为 String 类型。';

		    var html = this.tpl.replace(tplTag, function (a, tpl) {
		        var htmls = [];
		        for (var i = 0, j = data.length; i < j; i++) {
		            everyFn && everyFn(data[i], i, j);
		            htmls.push(replaceTpl.call(self, tpl, data[i]));
		        }
		
		        return htmls.join('');
		    }), html = replaceTpl.call(this, html, data);// 顶级替换	
		    
		    if(arguments[0]){ // 输出到 DOM
		    	if(typeof arguments[0] == 'string')
		    		document.getElementById(arguments[0]).innerHTML = html;
		    	else 
		    		arguments[0].innerHTML = html;
		    }

		    return html;
		}
    };

	/**
	 * 为每一项设置序号和总数 index/length 字段，供显示所用。
	 * 注意序号从 1 开始
	 * @param  {Object} item [description]
	 * @param  {Number} i    [description]
	 * @param  {Number} j    [description]
	 */
	exports.showIndex = function (item, i, j){
		item.index = i + 1;
		item.length = j;
	} 
});